#include "core.h"

#include <QDebug>

Core::Core()
{
    in_kbytes = 0;
    out_kbytes = 0;
    processed_packets = 0;
}

void Core::processPacket(PacketHeader packet)
{
    double datasize = packet.getDataSize();

    std::string src = packet.getSourceAddress();
    std::string tgt = packet.getDestinationAddress();

    if(src == ip) // In
        in_kbytes += (datasize/1024.0);

    if(tgt == ip) //Out
        out_kbytes += (datasize/1024.0);

    processed_packets++;

    struct iphdr ip_header   = packet.getIpHeader();
    struct tcphdr tcp_header = packet.getTcpHeader();

    u_int32_t saddr  = ip_header.saddr;
    u_int16_t source = tcp_header.source;

    u_int32_t daddr  = ip_header.daddr;
    u_int16_t dest   = tcp_header.dest;

    Flow flow(saddr,source,daddr,dest);
    flow.increaseBytes(ip_header.tot_len);

    // SYN
    if( packet.isSyn() ) {
        flows.push_back(flow);
        return;
    }

    // SYN + ACK
    if( packet.isSynAck() ) {

        int found = searchForFlow(flows,flow);

        if( found == NOT_FOUND )
            return;

        if( not flow._syn_ack )
            flows[found]._syn_ack = true;
        return;
    }

    // ACK
    if( packet.isAck() ) {

        int found = searchForFlow(flows,flow);

        if( found != NOT_FOUND ) {

            if( (not flow._ack) and (flow._syn_ack) ) {

                flows[found]._ack = true;

                //Flow Detected
                flows.erase(flows.begin()+found);
                initiated.push_back(flow);

            }

        }
        else {

            found = searchForFlow(initiated,flow);

            if( found == NOT_FOUND )
                return;

            initiated[found].increaseBytes(ip_header.tot_len);

        }

        return;

    }

    if( packet.isFin() ){

        int found = searchForFlow(initiated,flow);

        if( found == NOT_FOUND )
            return;

        initiated.erase(initiated.begin() + found);

    }

    // Any kind of packet

    int found = searchForFlow(initiated,flow);

    if( found == NOT_FOUND )
        return;

    initiated[found].increaseBytes(ip_header.tot_len);

}

double Core::getInByteS()
{
    return in_kbytes;
}

double Core::getOutByteS()
{
    return out_kbytes;
}

long Core::getPacketsCount()
{
    return processed_packets;
}

vector<Flow> Core::getInitiatedFlows()
{
    return initiated;
}

int Core::searchForFlow(vector<Flow> flows,Flow & flow)
{
    for( size_t i = 0 ; i < flows.size() ; i++ ) {
        if( flows[i] == flow ){
            flow = flows[i];
            return (int)(i);
        }
    }
    return NOT_FOUND;
}
